import websocket  # 同步WebSocket库
import json
import time
from typing import Optional, Dict, Callable
import threading

class WebSocketManager:
    def __init__(self):
        self.ws: Optional[websocket.WebSocket] = None  # 同步WebSocket对象
        self.callbacks = {}  # 存储方法对应的回调函数
        self.listening_thread = None  # 消息监听线程
        self.id_counter = 0  # 用于生成消息ID的计数器
        self.response_events = {}  # 用于存储每个请求的事件对象
        self.response_results = {}  # 用于存储每个请求的结果

    def get_websocket_ready_state(self) -> bool:
        """获取WebSocket连接状态"""
        if not self.ws:
            return False  # 未创建连接，视为已关闭
        return self.ws.connected

    def conn(self, protocol: str = "http") -> Optional[websocket.WebSocket]:
        """创建或获取WebSocket连接（同步版本）"""
        self._stop_listening_thread()

        current_state = self.get_websocket_ready_state()
        if current_state:
            return self.ws
        if not self.ws or not current_state:
            try:
                # 根据协议选择不同的连接地址
                if protocol == "http":
                    websocket_url = "ws://127.0.0.1:61232"
                else:
                    websocket_url = "wss://wss.singlewindow.cn:61231"

                print(f"使用{websocket_url}连接控件服务")

                # 创建新的WebSocket连接（同步操作）
                self.ws = websocket.create_connection(websocket_url, timeout=5)

                # 启动消息监听线程
                self.listening_thread = self._start_listening_thread()

            except Exception as ex:
                print(f"连接错误: {str(ex)}")
                self.ws = None

        return self.ws

    def _start_listening_thread(self):
        """启动消息监听线程"""
        def listen():
            while self.get_websocket_ready_state():  # 连接打开时持续监听
                try:
                    message = self.ws.recv()  # 同步接收消息
                    self._handle_message(message)
                except websocket.WebSocketConnectionClosedException:
                    print("连接已关闭，停止监听")
                    break
                except Exception as ex:
                    print(f"消息接收错误: {str(ex)}")
                    break

        thread = threading.Thread(target=listen, daemon=True)
        thread.start()
        return thread

    def _handle_message(self, message):
        """处理接收到的消息（同步版本）"""
        if isinstance(message, str) and message.startswith("{"):
            try:
                msg = json.loads(message)
                method = msg.get("_method")
                args = msg.get("_args", {})

                # 构建日志消息
                err_msg = f"调用{method}方法已返回, Result={args.get('Result')}"

                # 根据结果设置日志样式
                if args.get("Result"):
                    print(f"[信息] {err_msg}")
                else:
                    err_msg += f", CallbackInfos={message}"
                    print(f"[错误] {err_msg}")

                # 调用对应的回调函数
                if method in self.callbacks and callable(self.callbacks[method]):
                    self.callbacks[method](args, message)
                if method and method in self.response_events:
                    self.response_results[method] = args
                    self.response_events[method].set()
                    self.callbacks[method](args, message)

            except json.JSONDecodeError:
                print(f"数据格式非法: {message}")
        else:
            print(f"数据格式非法: {message}")

    def _stop_listening_thread(self) -> None:
        """安全停止监听线程（用标志位，避免自join）"""
        if not (self.listening_thread and self.listening_thread.is_alive()):
            return

        # 1. 标记为停止，让监听线程自行退出循环
        self.is_running = False

        # 2. 若连接存在，关闭连接触发recv()退出（加速线程停止）
        if self.ws and self.ws.connected:
            try:
                self.ws.close()
            except Exception as ex:
                print(f"关闭旧连接异常：{str(ex)}")

        # 3. 等待线程退出（最多2秒，避免无限阻塞）
        self.listening_thread.join(timeout=2)
        if self.listening_thread.is_alive():
            print("警告：监听线程未正常退出（可能存在资源泄漏）")
        else:
            print("旧监听线程已停止")

        # 4. 重置线程对象
        self.listening_thread = None


    def register_callback(self, method: str, callback: Callable) -> None:
        """注册方法对应的回调函数"""
        self.callbacks[method] = callback

    def send_message(self, message: str) -> None:
        """发送消息到WebSocket服务器（同步版本）"""
        if self.ws and self.get_websocket_ready_state():
            try:
                self.ws.send(message)
            except Exception as ex:
                print(f"发送消息失败: {str(ex)}")
        else:
            print("无法发送消息，连接未建立或已关闭")

    def is_connected_successfully(self, protocol: str = "http", max_retries: int = 3) -> bool:
        """
        检查连接是否成功的专用方法（同步版本）
        :param protocol: 协议类型（http/https）
        :param max_retries: 最大重试次数
        :return: 连接成功返回True，失败返回False
        """
        retry_count = 0
        while retry_count < max_retries:
            # 尝试建立连接
            self.conn(protocol)

            # 检查连接状态
            if self.get_websocket_ready_state():
                print("连接成功")
                return True

            # 重试前等待1秒
            retry_count += 1
            print(f"连接失败，正在进行第{retry_count}次重试...")
            time.sleep(1)  # 同步等待

        # 达到最大重试次数仍失败
        print(f"经过{max_retries}次重试，连接仍未成功")
        return False

    def base_invoke(self, method: str, args: Optional[Dict] = None, callback: Optional[Callable] = None) -> None:
        """
        实现JavaScript中的baseInvoke功能
        :param method: 要调用的方法名
        :param args: 方法参数（字典类型）
        :param callback: 回调函数，接收返回结果
        """
        # 参数处理：兼容省略args直接传递callback的情况
        if callable(args):
            callback = args
            args = {}

        # 确保连接已建立
        self.conn()

        # 打印调用日志
        print(f"\033[92m调用方法{method}\033[0m")  # 绿色文本

        # 注册回调函数
        if callback:
            self.callbacks[method] = callback

        # 构建消息体
        self.id_counter += 1  # 自增ID
        message_data = {
            "_method": method,
            "_id": self.id_counter,
            "args": args or {}  # 确保args不为None
        }

        # 转换为JSON字符串
        try:
            message_str = json.dumps(message_data)
        except json.JSONDecodeError as e:
            print(f"JSON序列化失败: {str(e)}")
            return

        # 根据连接状态发送消息
        if not self.get_websocket_ready_state():
            # 连接正在建立中，延迟发送
            print("连接正在建立中，延迟发送消息...")
            threading.Timer(0.5, self.send_message, args=[message_str]).start()
        else:
            # 直接发送消息
            self.send_message(message_str)


    def sync_base_invoke(self, method: str, args: Optional[Dict] = None,
                         timeout: int = 1) -> Optional[Dict]:
        """
        同步版本的base_invoke方法
        :param method: 要调用的方法名
        :param args: 方法参数（字典类型）
        :param timeout: 超时时间（秒），默认10秒
        :return: 服务器返回的结果字典，如果超时或出错则返回None
        """
        # 参数处理
        args = args or {}

        # 确保连接已建立
        self.conn()
        if not self.get_websocket_ready_state():
            print("无法建立WebSocket连接")
            return None

        # 打印调用日志
        print(f"\033[92m调用同步方法{method}\033[0m")

        # 创建事件对象用于等待响应
        event = threading.Event()
        self.response_events[method] = event
        self.response_results[method] = None  # 初始化结果存储

        try:
            # 构建消息体
            self.id_counter += 1
            message_data = {
                "_method": method,
                "_id": self.id_counter,
                "args": args
            }

            # 转换为JSON字符串
            try:
                message_str = json.dumps(message_data)
            except json.JSONDecodeError as e:
                print(f"JSON序列化失败: {str(e)}")
                return None

            # 6. 确保连接就绪后发送消息（最多等待2秒）
            wait_count = 0
            while not self.get_websocket_ready_state() and wait_count < 20:
                # 2. 关键修正：使用time.sleep，而非threading.sleep
                time.sleep(0.1)  # 每0.1秒检查一次，共等待2秒
                wait_count += 1
            if not self.get_websocket_ready_state():
                print(f"发送{method}消息失败：连接仍未就绪")
                return None

            self.send_message(message_str)

            # 等待响应，最多等待timeout秒
            success = event.wait(timeout)
            print(self.response_results)
            if not success:
                print(f"调用{method}超时({timeout}秒)")
                return None

            # 返回结果
            return self.response_results.get(method)

        finally:
            # 清理资源
            if method in self.response_events:
                del self.response_events[method]
            if method in self.response_results:
                del self.response_results[method]


    def close(self):
        """关闭WebSocket连接"""
        if self.ws:
            try:
                self.ws.close()
            except Exception as ex:
                print(f"关闭连接错误: {str(ex)}")
            self.ws = None


# 使用示例
def main():
    # 创建WebSocket管理器实例
    ws_manager = WebSocketManager()

    # 调用专用方法判断连接是否成功
    if ws_manager.is_connected_successfully(protocol="http"):
        print("有安装客户端")
        # 这里可以添加连接成功后的逻辑（如发送消息）
        # ws_manager.send_message(json.dumps({"action": "test"}))
    else:
        print("未安装客户端")
    #
    # # 保持程序运行一段时间以接收消息
    # try:
    #     while True:
    #         time.sleep(1)
    # except KeyboardInterrupt:
    #     print("程序已终止")
    # finally:
    #     ws_manager.close()


if __name__ == "__main__":
     # 延迟导入，仅在主程序运行时需要
    main()
